﻿using sorTV.Model;
using sorTV.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.ComponentModel;


namespace sorTV.Controller
{
    /// <summary>
    /// Lavet af Rasmus
    /// </summary>
    public class SystemController
    {
        #region Fields
        private bool? _automatisk;
        private int _antalManuelle;
        private static DBController _dbCon;
        private static int _logID;
        private BackgroundWorker _bgw;
        private Dictionary<int, ILog> _log;
        private bool _isRunning;
        private int _valgnummer;
        private List<bool> _regler;

        
        
        #endregion

        #region Constructor
        public SystemController()
        {
            _dbCon = new DBController();
            _valgnummer = _dbCon.NytValg(_dbCon.OpenConnection(0));
            _isRunning = false;
            _dbCon.CloseConnection(0);
            _log = new Dictionary<int, ILog>();
            _logID = 0;
            _regler = new List<bool>(){true,true,true,true};
        } 
        #endregion

        #region Metoder
        #region Transport System (Rasmus)
        #region Background work
        public void Start()
        {
            _log.Add(_logID++, LogMessage("Kørsel startet", ""));
            _isRunning = true;
            _bgw = new BackgroundWorker();
            _bgw.WorkerSupportsCancellation = true;
            _bgw.DoWork += bgw_DoWork;
            _bgw.RunWorkerAsync();
        }
        public void Stop()
        {
            _log.Add(_logID++, LogMessage("Kørsel stoppet", ""));
            _isRunning = false;
            _bgw.CancelAsync();
        }

        void bgw_DoWork(object sender, DoWorkEventArgs e)
        {
            while (_isRunning)
            {
                Step_Initial();
            }
        }
        #endregion


        #region Steps
        /// <summary>
        /// Denne Metode starter hele transport systemet og skal altid kaldes som det første.
        /// Metoden Opretter et nyt transport objekt med en XML-Fil hentet fra databasen og Step sat som Default Initial.
        /// Derefter sendes objektet til Dispatcher.
        /// Nuværende step: Initial
        /// Næste step: InitialParse
        /// </summary>
        public void Step_Initial()
        {
            _log.Add(_logID++, LogMessage("XML-fil hentes", ""));
            Transport trans = new Transport(HentXML());
            _log.Add(_logID++, LogMessage("XML-fil hentet", trans.Filnavn));
            Dispatcher(trans);
        }
        /// <summary>
        /// Denne Metode parser eller oversætter transport objektets XML fil til Objekter som i sidste ende vil ende i databasen.
        /// og sender der efter transporten videre til Dispatcher som håndterer objektet.
        /// Nuværende step: InitialParse
        /// Næste step: Regel
        /// </summary>
        /// <param name="trans"></param>
        public void Step_InitialParse(Transport trans)
        {
            _log.Add(_logID++, LogMessage("XML-fil oversættes", trans.Filnavn));
            trans.ValgData = XMLParser.ParseXML(trans.Document);
            _log.Add(_logID++, LogMessage("XML-fil oversat", trans.Filnavn));
            Dispatcher(trans);
        }
        /// <summary>
        /// Denne metode sender det oversatte data igennem en række prøver og check på værdier for at automatisk validerer 
        /// om det oversatte data ikke er forkert eller oversat forkert. transporten retuneres til dispatcher. i skrivende studn
        /// Er der ikke lavet noget logik til at håndterer dette derfor sættes flaget altid til 'true' for at objektet
        /// skal kunne vandre frit videre
        /// Nuværende step: Regel
        /// Næste step: ved false: ManGodkendelse | ved true: Auto
        /// </summary>
        /// <param name="trans"></param>
        public void Step_Regel(Transport trans)
        {
            foreach (var item in trans.ValgData)
            {
                Regel r = new Regel(item,_regler);
                item.Bestået = r.Resultat();
            }

            trans.Regel = true;

            foreach (var item in trans.ValgData)
            {
                if (item.Bestået == false)
                {
                    trans.Regel = false;
                    break;
                }
            }

            if (trans.Regel)
            {
                _log.Add(_logID++, LogMessage("XML-fil godkendt gennem filtre", trans.Filnavn));
            }
            else
            {
                _log.Add(_logID++, LogMessage("XML-fil fejlet et filter", trans.Filnavn));
            }
            Dispatcher(trans);
        }
        /// <summary>
        /// Denne metode tjekker på den globale angivelse af om systemet kører i automatisk eller manuel tilstand og sætter
        /// objektets flag til genkendelse af tilstand til den nuværende tilstand. objektet returneres til dispatcher.
        /// Nuværende step: Auto
        /// Næste step: ved false: ManGodkendelse | ved true: AutoUpload
        /// 
        /// </summary>
        /// <param name="trans"></param>
        public void Step_Auto(Transport trans)
        {
            if (_automatisk == true)
            {
                trans.Automatisk = true;
                _log.Add(_logID++, LogMessage("Systemtilstand: Automatisk", trans.Filnavn));
            }
            else if (_automatisk == false)
            {
                trans.Automatisk = false;
                _log.Add(_logID++, LogMessage("Systemtilstand: Manuel", trans.Filnavn));
            }

            Dispatcher(trans);
        }
        /// <summary>
        /// Denne metode er en 'endestation' for et objekt denne metode kaldes kun hvis alle tjeks er gennemført og systemets
        /// tilstand er sat til automatisk, efter denne metode uploades den oversatte xml-fil og transport objektet 'dør'
        /// Nuværende step: AutoUpload
        /// Næste step: intet
        /// </summary>
        /// <param name="trans"></param>
        public void Step_AutoUpload(Transport trans)
        {
            _log.Add(_logID++, LogMessage("Valgdata upload til database starter", trans.Filnavn));
            
            _dbCon.UploadTilDatabase(trans,_dbCon.OpenConnection(2),_valgnummer);
            _dbCon.CloseConnection(2);
            _log.Add(_logID++, LogMessage("Valgdata upload afsluttet", trans.Filnavn));
        }
        /// <summary>
        /// Denne metode er ligesom AutoUpload en 'endestation' for et objekt, dog er objektet endt her af en eller flere grunde
        /// enten er det fejlet på et filter eller en regel, ellers er tilstanden på systemet sat til manuelt. her uploades kun 
        /// objektets xml fil til en tabel i databasen hvorfra man på grænsefladen kan hentet objektet ud og manuelt verificerer 
        /// data enten ved sanity checks, eller ved at kontakte det ansvarlige valgsted
        /// eller i sidste instans afvise det. 
        /// Nuværnde step: ManUpload
        /// Næste step: intet
        /// </summary>
        /// <param name="trans"></param>
        public void Step_ManUpload(Transport trans)
        {
            _log.Add(_logID++, LogMessage("Upload af XML-fil til manuel behandling starter", trans.Filnavn));
            trans.Godkendt = true;

            _dbCon.SP_Manuel_Tilføje(trans, _dbCon.OpenConnection(3));
            _dbCon.CloseConnection(3);
            _log.Add(_logID++, LogMessage("XML-fil upload afsluttet", trans.Filnavn));
        }
        /// <summary>
        /// Denne metode modtager et transport objekt og sender det videre til upload til den manuelle tabel.
        /// returneres ikke til dispatcher.
        /// Nuværnde step: ManGodkendelse
        /// Næste step: ManUpload
        /// </summary>
        /// <param name="trans"></param>
        public void Step_ManGodkendelse(Transport trans)
        {
            _log.Add(_logID++, LogMessage("Manuel Godkendelse process startet", trans.Filnavn));
            Step_ManUpload(trans);
        }
        /// <summary>
        /// Denne metode opretter et nyt transport objekt og hent den næste xml-fil i køen af manuelle data der skal behandles.
        /// herefter returneres objektet til det step der kaldte metoden.
        /// Nuværende step: ManUdtræk
        /// Næste step: CustControlParse
        /// </summary>
        /// <returns></returns>
        public ITransport Step_ManUdtræk()
        {
            Transport trans = new Transport(HentManuelXML());
            _log.Add(_logID++, LogMessage("XML-fil udtrukket til manuel behandling", trans.Filnavn));
            return Step_CustControl(Step_CustControlParse(trans));
        }
        /// <summary>
        /// Objektet med dets oversatte xml-fil returners til GUI til repræsentation for brugeren og viderer behandling,
        /// dette er en 'endestation'
        /// Nuværende step: CustControl
        /// Næste step: intet. (Ender i GUI)
        /// </summary>
        /// <param name="trans"></param>
        /// <returns></returns>
        public ITransport Step_CustControl(ITransport trans)
        {
            return trans;
        }
        /// <summary>
        /// Denne metode modtager et objekt fra ManUdtræk steppet og oversætter objektets xml-fil og returnerer det til 
        /// det step der kaldte metoden.
        /// Nuværende step: CustControlParse
        /// Næste step: CustControl
        /// </summary>
        /// <param name="trans"></param>
        /// <returns></returns>
        public ITransport Step_CustControlParse(Transport trans)
        {
            trans.ValgData = XMLParser.ParseXML(trans.Document);
            _log.Add(_logID++, LogMessage("XML-fil parset til GUI", trans.Filnavn));
            return trans;
        }
        /// <summary>
        /// ENDNU IKKE IMPLEMENTERET!!
        /// Denne metode kaldes hvis man på GUI afviser en manuel fil, filen slettes ikke men lægges i en tabel med kasseret
        /// filer som via. Administrator adgang kan hentes ud igen og behandles enten via. den traditionelle strøm eller sættes
        /// direkte til manuel GUI behandling, (Disse metoder er endnu ikke implementeret)
        /// Nuværende step: ManKasseret
        /// Næste step: ukendt!
        /// </summary>
        /// <param name="trans"></param>
        public void Step_ManKasseret(Transport trans)
        {
            _log.Add(_logID++, LogMessage("XML-fil kasseret", trans.Filnavn));
            //////////////// UPLOAD TIL KASSERET TABEL
        }
        #endregion

        public void Dispatcher(Transport trans)
        {
            #region Step Check & Set next
            switch (trans.Step)
            {
                case TransportSteps.Initial:
                    trans.Step = TransportSteps.InitialParse;
                    break;
                case TransportSteps.InitialParse:
                    trans.Step = TransportSteps.Regel;
                    break;
                case TransportSteps.Regel:
                    if (trans.Regel)
                    {
                        trans.Step = TransportSteps.Auto;
                    }
                    else
                    {
                        trans.Step = TransportSteps.ManGodkendelse;
                    }

                    break;
                case TransportSteps.Auto:
                    if (trans.Automatisk == true)
                    {
                        trans.Step = TransportSteps.AutoUpload;
                    }
                    else if (trans.Automatisk == false)
                    {
                        trans.Step = TransportSteps.ManGodkendelse;
                    }
                    break;
                case TransportSteps.ManUpload:
                    if (trans.Godkendt)
                    {
                        trans.Step = TransportSteps.AutoUpload;
                    }
                    else
                    {
                        trans.Step = TransportSteps.ManKasseret;
                    }
                    break;

            }
            #endregion
            #region Step Check & Udfør Metode
            switch (trans.Step)
            {
                case TransportSteps.Initial:
                    break;
                case TransportSteps.InitialParse:
                    Step_InitialParse(trans);
                    break;
                case TransportSteps.Regel:
                    Step_Regel(trans);
                    break;
                case TransportSteps.Auto:
                    Step_Auto(trans);
                    break;
                case TransportSteps.AutoUpload:
                    Step_AutoUpload(trans);
                    break;
                case TransportSteps.ManUpload:
                    Step_ManUpload(trans);
                    break;
                case TransportSteps.ManGodkendelse:
                    Step_ManGodkendelse(trans);
                    break;

            }
            #endregion
        }
        #endregion

        #region System Log
        public ILog LogMessage(string handling, string filnavn)
        {
            Log retVal = null;
            if (filnavn == "")
            {
                retVal = new Log(handling, "System Handling");
            }
            else
            {
                retVal = new Log(handling, filnavn);
            }

            return retVal;
        }
        #endregion

        #region Hent Xml Metoder
        public Dictionary<XmlDocument, string> HentManuelXML()
        {
            
            Dictionary<XmlDocument, string> retVal = _dbCon.SP_Manuel_Udtræk(_dbCon.OpenConnection(2));
            _dbCon.CloseConnection(2);
            return retVal;
        }
        public Dictionary<XmlDocument, string> HentXML()
        {
            Dictionary<XmlDocument, string> retVal = _dbCon.SP_XML_Hent(_dbCon.OpenConnection(2));
            _dbCon.CloseConnection(2);
            return retVal;
        }
        #endregion

        #region XML-fil Uploader
        public void InsertXML(XmlDocument doc, string filnavn)
        {

            _dbCon.SP_XML_Insert(doc, filnavn, _dbCon.OpenConnection(1));
            _dbCon.CloseConnection(1);
        }
        #endregion

        #region 0-Kørsel Metoder
        public void NulKørsel(string xmlSti)
        {
            _dbCon.OpenConnection(0);
            XMLParser.NulKørsel(xmlSti);
            _dbCon.CloseConnection(0);
        }
        
        #endregion

        #region Nulstil Xml filer i databasen
        public void NulstilXMLFeeds()
        {
            _log.Add(_logID++, LogMessage("XML-filer nulstilles", ""));
            _dbCon.SP_XML_Nulstil(_dbCon.OpenConnection(1));
            _dbCon.CloseConnection(1);
            _log.Add(_logID++, LogMessage("XML-filer nulstillet", ""));
        }
        #endregion

        #region Geo Data Metoder
        public string GeoDataAO(int stedId, int gkid)
        {
            
            string retVal = _dbCon.SP_Manuel_GeoData_AO(stedId, gkid, _dbCon.OpenConnection(3));
            _dbCon.CloseConnection(3);
            return retVal;
        }
        public string GeoDataKommune(int gkid)
        {
            string retVal = _dbCon.SP_Manuel_GeoData_Kommune(gkid, _dbCon.OpenConnection(3));
            _dbCon.CloseConnection(3);
            return retVal;
        }
        public string GeoDataKreds(int gvid)
        {
            
            string retVal = _dbCon.SP_Manuel_GeoData_Kreds(gvid, _dbCon.OpenConnection(3));
            _dbCon.CloseConnection(3);
            return retVal;
        }
        public string GeoDataAmtstorkreds(int gaid)
        {

            string retVal = _dbCon.SP_Manuel_GeoData_Amtstorkreds(gaid, _dbCon.OpenConnection(3));
            _dbCon.CloseConnection(3);
            return retVal;
        }
        #endregion 
        #endregion

        #region Properties
        public List<bool> Regler
        {
            get { return _regler; }
            set { _regler = value; }
        }
        public bool? Automatisk
        {
            get { return _automatisk; }
            set { _automatisk = value; }
        }

        public int AntalManuelleFiler
        {
            get
            {
                _antalManuelle = _dbCon.SP_Manuel_Antal(_dbCon.OpenConnection(0));
                _dbCon.CloseConnection(0);
                return _antalManuelle;
            }
        }

        public Dictionary<int, ILog> Log
        {
            get { return _log; }
        }

        public List<ILog> LogValues
        {
            get
            {
                return Log.Values.ToList();
            }
        }

        public Dictionary<string, int> Resultat
        {
            get
            {
                Dictionary<string,int> retVal = _dbCon.HentResultat(_dbCon.OpenConnection(4),_valgnummer);
                _dbCon.CloseConnection(4);
                return retVal;
            }
        }

        public int Valgnummer
        {
            get { return _valgnummer; }
            set { _valgnummer = value; }
        }
        #endregion
    }
}
